const path = require('path'); // nodejs核心模块, 专门处理路径问题
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const os = require('os');
const TerserWebpackPlugin = require("terser-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");

// cpu核数
const threads = os.cpus().length;

// 获取处理样式的loader
function getStyleLoader(pre) {
  return [
    MiniCssExtractPlugin.loader, // 提取css成单独文件
    'css-loader', // 将css资源编译成commonjs的模块到js中
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    pre
  ].filter(Boolean);
}
module.exports = {
  // 入口
  entry: './src/main.js',
  // entry: {
  //   app: './src/app.js',
  //   main: './src/main.js'
  // },
  // 输出
  output: {
    // __dirname 是nodejs变量, 代表当前文件夹目录
    path: path.resolve(__dirname, '../dist'),
    // 入口文件打包后的文件名(文件位置&文件名)
    filename: 'static/js/main.js', // 打包后的文件名
    // filename: '[name].js',
    clean: true, // 自动清空上次打包结果, 原理是将path整个目录清空,在进行打包
  },
  // 加载器
  module: {
    rules: [
      {
        // 每个文件只能被一个loader处理, 提高打包速度, 避免重复处理
        oneOf: [
          {
            test: /\.css$/i,
            use: getStyleLoader(), // 执行顺序, 从右向左, 从下向上
          },
          {
            test: /\.less$/i,
            // loader: 'xxx', // 只能使用一个loader
            use: getStyleLoader('less-loader'),
          },
          {
            test: /\.s[ac]ss$/i,
            use: getStyleLoader('sass-loader'),
          },
          {
            test: /\.styl$/,
            // loader: 'stylus-loader', // 将 Stylus 文件编译为 CSS
            use: getStyleLoader('stylus-loader'),
          },
          // { // 处理图片资源 webpack5 已经内置
          //   test: /\.(png|jpe?g|gif|webp)$/,
          //   type: "asset",
          // },
          {
            test: /\.(png|jpe?g|gif|svg|webp)$/,
            type: 'asset', // asset 会转base64格式
            parser: {
              dataUrlCondition: { // 匹配的资源图片大小如果小于下面的配置会自动转为base64格式,减少请求
                maxSize: 50 * 1024 // 50kb
              }
            },
            generator: { 
              // 静态资源存放目录
              // hash:10 文件哈希值只要10位
              filename: 'static/images/[hash:10][ext][query]'
            }
          },
          { // 处理字体图标&视频&音频等
            test: /\.(ttf|woff2?|mp3|mp4|avi)$/,
            type: 'asset/resource',
            generator: { 
              // 静态资源存放目录
              // hash:10 文件哈希值只要10位
              filename: 'static/media/[hash:10][ext][query]'
            }
          },
          {
            test: /\.js$/,
            // exclude: /node_modules/, // 要排除的文件, 排除node_modules文件中的js文件(不处理) 
            include: path.resolve(__dirname, '../src'), // 只处理src目录下的js文件
            use: [
              {
                loader: 'thread-loader', // 开启多线程
                options: {
                  works: threads, // 线程数量
                }
              },
              {
                loader: 'babel-loader', // es6转es5
                options: {
                  // presets: ['@babel/preset-env'], // 可在这个地方写, 也可以在项目根目录创建babel.config.js文件来写
                  cacheDirectory: true, // 开启babel缓存
                  cacheCompression: false, // 关闭缓存文件压缩
                  plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
                },
              }
            ]
          },
        ]
      }
    ]
  },
  // 插件
  plugins: [
    new ESLintPlugin({
      // context 只检测当前目录下的src文件下的文件
      context: path.resolve(__dirname, '../src'),
      exclude: 'node_modules', // 不检测node_modules目录下的文件(默认值:node_modules)
      cache: true,
      cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslint-cache'), // 设置缓存
      threads, // 开启多线程
    }),
    new HtmlWebpackPlugin({
      // 以public/index.html文件下的index.html为模板创建新的HTML文件, 会保存index.html文件的内容
      template: path.resolve(__dirname, '../public/index.html')
    }),
    new MiniCssExtractPlugin({ // 提取css成单独文件
      filename: 'static/css/main.css'
    }),
    // new CssMinimizerPlugin(), // css压缩
    // new TerserWebpackPlugin({
    //   parallel: threads, // 开启多线程
    // })
  ],
  optimization: {
    // 代码分割
    splitChunks: {
      chunks: 'all',
      // 其余配置采用默认值
    },
    // 压缩操作
    minimizer: [ // webpack 5 推荐放在这个配置下进行优化
      // css压缩
      new CssMinimizerPlugin(), 
      // js 压缩
      new TerserWebpackPlugin({
        parallel: threads, // 开启多线程压缩
      }),
      // 压缩图片
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", { interlaced: true }],
              ["jpegtran", { progressive: true }],
              ["optipng", { optimizationLevel: 5 }],
              [
                "svgo",
                {
                  plugins: [
                    "preset-default",
                    "prefixIds",
                    {
                      name: "sortAttrs",
                      params: {
                        xmlnsOrder: "alphabetical",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      }),
    ]
  },
  // 模式
  mode: 'production',
  devtool: 'source-map', // 构建行和列的对应关系
};
